package com.zou.mall.member.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.zou.common.to.CategoryTo;
import com.zou.common.utils.R;
import com.zou.mall.member.feign.CategoryFeignService;
import com.zou.mall.member.feign.CouponFeignService;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.*;

/**
 * 配置RefreshScope后
 * Value都会从nacos配置中拉取数据
 */
@Api("member demo")
@RefreshScope
@RestController
@RequestMapping("member/demo")
@Slf4j
public class DemoController {

    @Autowired
    private CouponFeignService couponFeignService;

    @Autowired
    CategoryFeignService categoryFeignService;

    /** Config k调用步骤
     * 1. 添加配置依赖。。
     * 2. 本地创建bootstrap.properties,并连接到nacos的配置中心地址
     * 3. 在nacos配置中添加服务配置集，命名规则：服务名.properties
     * 4. 在类上添加注解RefreshScope
     * 5. 之后变量优先读取配置中心的配置集，实现动态刷新
     */
    @Value("${member.username}")
    private String username;

    /**
     * feign k调用步骤：
     * 1. 引入openFeign依赖
     * 2. 编写要去依赖的接口
     * 3. 创建feignservice ,写你想调用的方法
     * 4. 开启远程调用功能,并引入调用的包
     */
    @GetMapping("/feign-test")
    public R feignTest(){
        R r = couponFeignService.memberCoupons();
        r.put("username",username);
        System.out.println(r);
        return r;
    }

    /**
     * 自定义受保护资源
     * @SentinelResource
     * value 定义被控资源名称
     * blockHandler针对回调的方法，需要在此类写相同的降级方法
     * fallback 针对异常的统一处理
     *
     * @return
     */
    @SentinelResource(value = "getseckilltree",blockHandler = "blockHandler")
    @GetMapping("/prod/tree")
    public R listTreeByCategory() {
        //自定义名称限流,方法一
        try (Entry entry = SphU.entry("seckilltree")) {
            Thread.sleep(1500);
        } catch (BlockException e) {
            //资源访问阻止,被限流或被降级
            //在此处进行相应的降级操作
            log.error("资源被限流{}-------------->", e.getMessage());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        return categoryFeignService.listTree2();
    }

    @PostMapping("/prod/save")
    public R saveCategory(@RequestBody CategoryTo to) {
        return categoryFeignService.save(to);
    }

    /**
     * @SentinelResource的降级方法
     * 返回值和入参要一致,兜底方法要多个方法入参(BlockException)
     * @param ex
     * @return
     */
    public R blockHandler(BlockException ex){
        return R.error("error: "+ex);
    }

}
